package com.alibaba.citrus.cr.forecast.repository.impl;

import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.annotation.RepositoryInvoker;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.forecast.common.DateUtils;
import com.alibaba.citrus.cr.forecast.common.MoneyUtil;
import com.alibaba.citrus.cr.forecast.facade.service.ForecastOrderWriteServiceImpl;
import com.alibaba.citrus.cr.forecast.functions.forecastorder.constants.ForecastConstants;
import com.alibaba.citrus.cr.forecast.repository.ForecastOrderLineQueryRepository;
import com.alibaba.citrus.cr.forecast.repository.ForecastOrderQueryRepository;
import com.alibaba.citrus.cr.forecast.repository.impl.converter.ForecastOrderRepositoryConverter;
import com.alibaba.citrus.cr.sales.plan.api.salesplan.SalesPlanQueryService;
import com.alibaba.citrus.cr.sales.plan.api.statistics.SalesPlanScItemStatQueryService;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.PageQuerySalePlanRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QueryPlanScItemStatRequest;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanStatusEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesStatBizTypeEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.StatPoolTypeEnum;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanStatScItemSDO;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.page.PageResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.esdegrade.dto.GetEsDegradeValueResponse;
import com.epoch.app.bcorder.esdegrade.service.EsDegradeService;
import com.epoch.app.bcorder.model.dto.PageQuerySalesPlanLineList2Request;
import com.epoch.app.bcorder.model.dto.PageQuerySalesPlanLineList2Response;
import com.epoch.app.bcorder.model.dto.SalesPlanLineSDO2;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.SalesPlanService;
import com.epoch.app.crb2btradecenter.api.orderquery.service.OrderQueryService;
import com.epoch.app.crb2btradecenter.model.dto.*;
import com.epoch.app.crb2btradecenter.service.CrB2bTradeCenterService;
import com.epoch.app.crforecastsales.domian.forecastorder.model.ForecastOrder;
import com.epoch.app.crforecastsales.domian.forecastorder.service.ForecastOrderService;
import com.epoch.app.crforecastsales.domian.forecastorderline.dto.*;
import com.epoch.app.crforecastsales.domian.forecastorderline.model.ForecastOrderLine;
import com.epoch.app.crforecastsales.domian.forecastorderline.service.ForecastOrderLineService;
import com.epoch.app.crforecastsales.dto.request.DealForecastListRequest;
import com.epoch.app.crforecastsales.dto.response.DealForecastOrderResponse;
import com.epoch.app.crforecastsales.dto.response.QueryForecastLineResponse;
import com.epoch.app.crforecastsales.forecastorderlineindex.model.ForecastOrderLineIndex;
import com.epoch.app.crforecastsales.forecastorderlineindex.service.ForecastOrderLineIndexService;
import com.epoch.app.crforecastsales.model.dto.ActivitySDO;
import com.epoch.app.crforecastsales.model.dto.BatchQueryByIdsRequest;
import com.epoch.app.crforecastsales.model.dto.SearchForecastOrderRequest;
import com.epoch.app.crforecastsales.model.dto.SelectCombox;
import com.epoch.app.crforecastsales.sdo.ForecastOrderLineSDO;
import com.epoch.app.crforecastsales.sdo.ForecastOrderSDO;
import com.epoch.app.crplatformenhance.inventoryallotquery.service.InventoryAllotQueryService;
import com.epoch.app.crplatformenhance.model.dto.*;
import com.epoch.app.crplatformenhance.sdo.CustomerAddressSDO;
import com.epoch.app.crplatformenhance.service.CrPlatformEnhanceService;
import com.epoch.app.crpricecenter.api.creditquery.dto.BatchQueryCreditListRequest;
import com.epoch.app.crpricecenter.api.creditquery.service.CreditQueryService;
import com.epoch.app.crpricecenter.api.pricequery.service.PriceQueryService;
import com.epoch.app.crpricecenter.dto.request.*;
import com.epoch.app.crpricecenter.dto.response.ItemPriceResponse;
import com.epoch.app.crpricecenter.dto.response.PriceQueryResponse;
import com.epoch.app.crpricecenter.model.dto.CreditInfoSDO;
import com.epoch.app.crpricecenter.model.dto.CreditQueryRequest;
import com.epoch.app.crunifiedinventory.model.dto.*;
import com.epoch.app.crunifiedinventory.service.CrUnifiedInventoryService;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author: qiaojiange
 * @create: 2021/09/15
 * @Description 预报单子单查询
 */
@Service
public class ForecastOrderLineQueryRepositoryImpl implements ForecastOrderLineQueryRepository {

    private static Log log = LogFactory.getLog(ForecastOrderLineQueryRepositoryImpl.class);

    private static final com.alibaba.cz.base.tool.log.Log logger = com.alibaba.cz.base.tool.log.Log.getLogger(ForecastOrderWriteServiceImpl.class);

    @Autowired
    private InventoryAllotQueryService inventoryAllotQueryService;
    @Resource
    ForecastOrderLineService forecastOrderLineService;
    @Resource
    ForecastOrderQueryRepository forecastOrderQueryRepository;
    @Resource
    PriceQueryService priceQueryService;
    @Resource
    ForecastOrderLineIndexService forecastOrderLineIndexService;
    @Autowired
    BaseDataService baseDataService;
    @Autowired
    CreditQueryService creditQueryService;
    @Autowired
    private SalesPlanService salesPlanService;
    @Autowired
    private CrB2bTradeCenterService crB2bTradeCenterService;
    @Autowired
    private SalesPlanQueryService salesPlanQueryService;
    @Autowired
    CrPlatformEnhanceService crPlatformEnhanceService;
    @Resource
    private SalesPlanScItemStatQueryService salesPlanScItemStatQueryService;

    @Resource
    private OrderQueryService orderQueryService;
    @Resource
    ForecastOrderService forecastOrderService;
    @Autowired
    private CrUnifiedInventoryService crUnifiedInventoryService;

    @Resource(name = "scItemsQueryTaskExecutor")
    private ThreadPoolTaskExecutor scItemsQueryTaskExecutor;

    @Resource(name = "monthSalesReportTaskExecutor")
    ThreadPoolTaskExecutor monthSalesReportTaskExecutor;

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private EsDegradeService esDegradeService;

    @Resource
    CrUnifiedInventoryService unifiedInventoryService;


    private static final String REPORTED_QUANTITY = "reported";
    private static final String REMAIN_QUANTITY = "remain";

    // 每日库存查询循环查询较多， 参数重复度高， 增加30秒的缓存
    Cache<String, QueryResolveInventoryResponse> inventoryCache = CacheBuilder.newBuilder()
        .maximumSize(3000) // 设置缓存的最大容量
        .expireAfterWrite(60, TimeUnit.SECONDS) // 设置缓存在写入一分钟后失效
        .concurrencyLevel(10) // 设置并发级别为10
        .recordStats() // 开启缓存统计
        .build();

    // 每日库存查询循环查询较多， 参数重复度高， 增加30秒的缓存
    Cache<String, DailyInventoryLine> dailyInventoryCache = CacheBuilder.newBuilder()
        .maximumSize(3000) // 设置缓存的最大容量
        .expireAfterWrite(60, TimeUnit.SECONDS) // 设置缓存在写入一分钟后失效
        .concurrencyLevel(10) // 设置并发级别为10
        .recordStats() // 开启缓存统计
        .build();

    @Override
    @RepositoryInvoker(printLog = true)
    public List<ForecastOrderLineSDO> queyrLineDetailList(ForecastOrderLineSDO sdo) {
        //根据主订单查询子单集合
        ForecastOrderLine forecastOrderLineLoadListRequest = new ForecastOrderLine();
        forecastOrderLineLoadListRequest.setMainOrderId(sdo.getMainOrderId());
        forecastOrderLineLoadListRequest.setScItemId(sdo.getScItemId());
        Result<List<ForecastOrderLine>> listResult = forecastOrderLineService.loadForecastOrderLineList(
            forecastOrderLineLoadListRequest);
        List<ForecastOrderLine> result = listResult.getResult();
        //结果封装转换
        List<ForecastOrderLineSDO> forecastOrderLineSDOArrayList = null;
        if (CollectionUtils.isNotEmpty(result)) {
            forecastOrderLineSDOArrayList = result.stream().map(forecastOrderLine -> {
                ForecastOrderLineSDO forecastOrderLineSDO = new ForecastOrderLineSDO();
                //            BeanUtils.copyProperties(forecastOrderLine,forecastOrderLineSDO);
                forecastOrderLineSDO.setId(forecastOrderLine.getId());
                forecastOrderLineSDO.setDealStatus(forecastOrderLine.getDealStatus());
                //                forecastOrderLineSDO.setGmtCreate(forecastOrderLine.getGmtCreate());
                //                forecastOrderLineSDO.setGmtModified(forecastOrderLine.getGmtModified());
                forecastOrderLineSDO.setGmtCreate(forecastOrderLine.getGmt_create());
                forecastOrderLineSDO.setGmtModified(forecastOrderLine.getGmt_modified());
                forecastOrderLineSDO.setCreatorId(forecastOrderLine.getCreatorId());
                forecastOrderLineSDO.setModifierId(forecastOrderLine.getModifierId());
                forecastOrderLineSDO.setCreatorName(forecastOrderLine.getCreatorName());
                forecastOrderLineSDO.setModifierName(forecastOrderLine.getModifierName());
                forecastOrderLineSDO.setBizCode(forecastOrderLine.getBizCode());
                forecastOrderLineSDO.setOuterLineId(forecastOrderLine.getOuterLineId());
                forecastOrderLineSDO.setMainOrderId(forecastOrderLine.getMainOrderId());
                forecastOrderLineSDO.setStatus(forecastOrderLine.getStatus());
                forecastOrderLineSDO.setScItemOutCode(forecastOrderLine.getScItemOutCode());
                forecastOrderLineSDO.setCollectStatus(forecastOrderLine.getCollectStatus());
                forecastOrderLineSDO.setAllowCollectAmount(forecastOrderLine.getAllowCollectAmount());
                forecastOrderLineSDO.setCreatorName(forecastOrderLine.getCreatorName());
                forecastOrderLineSDO.setAnalysisReason(forecastOrderLine.getAnalysisReason());
                forecastOrderLineSDO.setAnalysisTime(forecastOrderLine.getAnalysisTime());
                forecastOrderLineSDO.setIdemId(forecastOrderLine.getIdemId());
                forecastOrderLineSDO.setActivityName(forecastOrderLine.getActivityName());
                forecastOrderLineSDO.setActivityCode(forecastOrderLine.getActivityCode());

                Map<String, String> features = (Map)JSONObject.parseObject(forecastOrderLine.getFeatures());
                if (MapUtils.isNotEmpty(features)) {
                    String activityNumber = features.get(ForecastConstants.ACTIVITY_NUMBER);
                    String goodsCode = features.get(ForecastConstants.GOODS_CODE);
                    List<ActivitySDO> activitySDOS = JSONObject.parseArray(
                        JSON.toJSONString(features.get(ForecastConstants.ACTIVITY_DETAILS)), ActivitySDO.class);
                    if (CollectionUtils.isNotEmpty(activitySDOS)) {
                        List<String> collect = activitySDOS.stream().map(ActivitySDO::getActivityTermid).collect(
                            Collectors.toList());
                        activityNumber = collect.stream().collect(Collectors.joining("-"));
                    }
                    forecastOrderLineSDO.setActivityNumber(activityNumber);
                    forecastOrderLineSDO.setGoodsCode(goodsCode);
                    forecastOrderLineSDO.setActivityPriceRemark(features.get(ForecastConstants.ACTIVITY_PRICE_REMARK));
                }
                if (Objects.nonNull(forecastOrderLine.getScItemOutCode())) {
                    forecastOrderLineSDO.setGoodsCode(forecastOrderLine.getScItemOutCode());
                }
                forecastOrderLineSDO.setCustomerCode(forecastOrderLine.getCustomerCode());
                forecastOrderLineSDO.setSerialNumber(forecastOrderLine.getSerialNumber());
                forecastOrderLineSDO.setDepartmentCode(forecastOrderLine.getDepartmentCode());
                forecastOrderLineSDO.setScItemId(forecastOrderLine.getScItemId());
                forecastOrderLineSDO.setScItemTitle(forecastOrderLine.getScItemTitle());
                forecastOrderLineSDO.setPredictReplyAmount(forecastOrderLine.getPredictReplyAmount());
                forecastOrderLineSDO.setQuantity(forecastOrderLine.getQuantity());
                forecastOrderLineSDO.setUnitPrice(forecastOrderLine.getUnitPrice());
                forecastOrderLineSDO.setTotalFee(forecastOrderLine.getTotalFee());
                forecastOrderLineSDO.setActivityPrice(forecastOrderLine.getActivityPrice());
                forecastOrderLineSDO.setTotalActivityFee(forecastOrderLine.getTotalActivityFee());
                forecastOrderLineSDO.setActualTotalReplyAmount(forecastOrderLine.getActualTotalReplyAmount());
                forecastOrderLineSDO.setShouldPayFee(forecastOrderLine.getShouldPayFee());
                forecastOrderLineSDO.setDiscountFee(forecastOrderLine.getDiscountFee());
                forecastOrderLineSDO.setDetailRemark(forecastOrderLine.getDetailRemark());
                forecastOrderLineSDO.setReplyStatus(forecastOrderLine.getReplyStatus());
                forecastOrderLineSDO.setReplyTime(forecastOrderLine.getReplyTime());
                forecastOrderLineSDO.setRefuseReason(forecastOrderLine.getRefuseReason());
                forecastOrderLineSDO.setConfirmTime(forecastOrderLine.getConfirmTime());
                forecastOrderLineSDO.setConfirmStatus(forecastOrderLine.getConfirmStatus());
                forecastOrderLineSDO.setFinishedTime(forecastOrderLine.getFinishedTime());
                forecastOrderLineSDO.setInventoryUnit(forecastOrderLine.getInventoryUnit());
                forecastOrderLineSDO.setInventoryUnitCode(forecastOrderLine.getInventoryUnitCode());
                forecastOrderLineSDO.setSaleUnit(forecastOrderLine.getSaleUnit());
                forecastOrderLineSDO.setSaleUnitCode(forecastOrderLine.getSaleUnitcode());
                forecastOrderLineSDO.setWarehouseArea(forecastOrderLine.getWarehouseArea());
                forecastOrderLineSDO.setUnitConvert(forecastOrderLine.getUnitConvert());
                forecastOrderLineSDO.setWarehouseLocation(forecastOrderLine.getWarehouseLocation());
                forecastOrderLineSDO.setSyncVersion(forecastOrderLine.getSyncVersion());
                forecastOrderLineSDO.setTenantId(forecastOrderLine.getTenantId());
                forecastOrderLineSDO.setFeatures(forecastOrderLine.getFeatures() == null ? null
                    : (Map)JSONObject.parseObject(forecastOrderLine.getFeatures()));
                forecastOrderLineSDO.setExt(forecastOrderLine.getExt());
                forecastOrderLineSDO.setExt1(forecastOrderLine.getExt1());
                forecastOrderLineSDO.setExt2(forecastOrderLine.getExt2());
                forecastOrderLineSDO.setExt3(forecastOrderLine.getExt3());
                forecastOrderLineSDO.setExt4(forecastOrderLine.getExt4());
                forecastOrderLineSDO.setExt5(forecastOrderLine.getExt5());

                List<SelectCombox> selectComboxes = new ArrayList<>();
                SelectCombox selectCombox = new SelectCombox();
                if (StringUtils.isNotEmpty(forecastOrderLine.getSaleUnitcode())) {
                    selectCombox.setValue(forecastOrderLine.getSaleUnitcode());
                }
                if (StringUtils.isNotEmpty(forecastOrderLine.getSaleUnit())) {
                    selectCombox.setLabel(forecastOrderLine.getSaleUnit());
                }
                selectComboxes.add(selectCombox);
                forecastOrderLineSDO.setSaleUnitList(selectComboxes);

                return forecastOrderLineSDO;
            }).collect(Collectors.toList());
            Collections.sort(forecastOrderLineSDOArrayList, new Comparator<ForecastOrderLineSDO>() {
                @Override
                public int compare(ForecastOrderLineSDO o1, ForecastOrderLineSDO o2) {
                    if (Integer.parseInt(o1.getSerialNumber()) > Integer.parseInt(o2.getSerialNumber())) {
                        return 1;
                    }
                    if (Integer.parseInt(o1.getSerialNumber()) == Integer.parseInt(o2.getSerialNumber())) {
                        return 0;
                    }
                    return -1;
                }
            });
        }
        return forecastOrderLineSDOArrayList;
    }

    @Override
    @RepositoryInvoker
    public ForecastOrderLineSDO query(String id) {
        LoadForecastOrderLineRequest loadForecastOrderLineRequest = new LoadForecastOrderLineRequest();
        loadForecastOrderLineRequest.setId(id);
        ForecastOrderLine forecastOrderLine = forecastOrderLineService.loadForecastOrderLine(
            loadForecastOrderLineRequest);
        ForecastOrderLineSDO forecastOrderLineSDO = ForecastOrderRepositoryConverter.toForecastOrderLineSDO(
            forecastOrderLine);
        return forecastOrderLineSDO;
    }

    /**
     * 根据ids查询子订单列表
     *
     * @param
     * @return
     */
    @Override
    @RepositoryInvoker
    @NotNull
    public PageResult<List<ForecastOrderLineSDO>> batchLoadList(List<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return PageResult.empty();
        }
        BatchLoadListRequest forecastOrderLineLoadListRequest = new BatchLoadListRequest();
        forecastOrderLineLoadListRequest.setIds(ids);
        try {
            BatchLoadListResponse batchLoadListResponse = forecastOrderLineService.batchLoadList(forecastOrderLineLoadListRequest);
            logger.info("batchLoadListResponse结果:{}", JSON.toJSONString(batchLoadListResponse));
            List<ForecastOrderLineSDO> collect = Nullable.stream(batchLoadListResponse.getResult())
                    .map(ForecastOrderRepositoryConverter::toForecastOrderLineSDO)
                    .collect(Collectors.toList());

            return PageResult.of(collect, batchLoadListResponse.getResult().size());
        } catch (Exception e) {
            log.error("批量查询子订单列表失败", e);
        }
        return PageResult.empty();
    }

    @Override
    @RepositoryInvoker
    public List<ForecastOrderLineSDO> batchForecastOrderLineList(List<String> ids) {
        List<ForecastOrderLine> forecastOrderLines1 = new ArrayList<>();
        for (String id : ids) {
            ForecastOrderLine forecastOrderLineLoadListRequest = new ForecastOrderLine();
            forecastOrderLineLoadListRequest.setId(Long.parseLong(id));
            Result<List<ForecastOrderLine>> listResult = forecastOrderLineService.loadForecastOrderLineList(
                forecastOrderLineLoadListRequest);
            List<ForecastOrderLine> result = listResult.getResult();
            forecastOrderLines1.addAll(result);
        }
        log.info("明细行行数" + forecastOrderLines1.size());
        BatchLoadListRequest forecastOrderLineLoadListRequest = new BatchLoadListRequest();
        forecastOrderLineLoadListRequest.setIds(ids);
        BatchLoadListResponse batchLoadListResponse = forecastOrderLineService.batchLoadList(
            forecastOrderLineLoadListRequest);
        List<ForecastOrderLineSDO> collect = Nullable.stream(forecastOrderLines1).map(
            ForecastOrderRepositoryConverter::toForecastOrderLineSDO).collect(Collectors.toList());
        return collect;

    }

    @Override
    @RepositoryInvoker
    public Result<List<QueryForecastLineResponse>> pageQuery(SearchForecastOrderRequest pageQueryForecastRequest) {
        long l1 = new Date().getTime();
        Integer oriLimit = pageQueryForecastRequest.getLimit();
        // 纪元分页查询， 限制每页返回条数最大是1000条数据， 预报回复页面要返回全部数据
        Result<List<ForecastOrderLineIndex>> forecastOrderLineIndicesResult = queryForecastOrderLines(
            pageQueryForecastRequest);

        if (Objects.isNull(forecastOrderLineIndicesResult) || CollectionUtils.isEmpty(
            forecastOrderLineIndicesResult.getResult())) {
            return Result.success(null);
        }
        long l2 = new Date().getTime();
        log.info("查询es耗时:" + (l2 - l1));
        // 获取当前列表中的订单的销售组织列表
        Set<String> organizationCodeList = Sets.newConcurrentHashSet();
        // 货品按照仓库进行分组
        Map<String, Set<String>> itemWarehoseGroup = Maps.newHashMap();
        //        Map<String,AllotOrderLineSDO>
        Set<String> allotOrderLineIds = Sets.newConcurrentHashSet();

        List<ForecastOrderLineIndex> forecastOrderLineIndices = forecastOrderLineIndicesResult.getResult();
        for (ForecastOrderLineIndex forecastOrderLineIndex : forecastOrderLineIndices) {
            organizationCodeList.add(forecastOrderLineIndex.getMainOrganizationCode());
            //统计每日库存占用的id
            Map<String, Object> features = JSONObject.parseObject(forecastOrderLineIndex.getSubFeatures());
            if (MapUtils.isNotEmpty(features) && Objects.nonNull(
                features.get(ForecastConstants.DISINTEGRATION_ALLOT_LINE_ID))) {
                allotOrderLineIds.add(features.get(ForecastConstants.DISINTEGRATION_ALLOT_LINE_ID).toString());
            }
            // 按照仓库将货品分组
            String mainWareHouseCode = forecastOrderLineIndex.getMainWareHouseCode();
            String subScItemId = forecastOrderLineIndex.getSubScItemId();

            Set<String> scItemSets = itemWarehoseGroup.get(mainWareHouseCode);
            if (scItemSets == null) {
                scItemSets = Sets.newHashSet();
                itemWarehoseGroup.put(mainWareHouseCode, scItemSets);
            }
            scItemSets.add(subScItemId);
        }
        long l3 = new Date().getTime();
        log.info("循环耗时:" + (l3 - l2));
        // 获取当天提报的预报单数据
        Map<String, Map<String, Integer>> statMap = statTodayForecastOrder(organizationCodeList);
        long l4 = new Date().getTime();
        log.info("获取当天预报单数据耗时:" + (l4 - l3));
        //批量查询每日库存
        List<String> allotIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(allotOrderLineIds)) {
            allotIds = new ArrayList<>(allotOrderLineIds);
        }
        this.getBelongDailyInventoryList(allotIds);
        // 批量查询库存
        Map<String, String> inventoryMap = Maps.newHashMap();

        List<String> warehouseIds = Lists.newArrayList();
        warehouseIds.addAll(itemWarehoseGroup.keySet());
        List<String> goodsIds = Lists.newArrayList();
        itemWarehoseGroup.values().forEach(goodsIds::addAll
        );
        List<String> goodsIdsDistinct = goodsIds.stream().distinct().collect(Collectors.toList());
        List<ForecastAnalysisInventoryRequest> availableInventoryQueryList = new ArrayList<>();
        // 获取可用库存
        ForecastAnalysisQueryInventoryRequest analysisQueryInventoryRequest = ForecastAnalysisQueryInventoryRequest
            .builder()
            .goodsIds(goodsIdsDistinct)
            .types(Lists.newArrayList(2, 3))
            .warehouseAreaIdList(warehouseIds)
            .start(0)
            .limit(1000).build();

        Result<List<ForecastAnalysisInventoryRequest>> forecastAnalysisQueryInventory =
            crUnifiedInventoryService.forecastAnalysisQueryInventory(analysisQueryInventoryRequest);
        long l55 = new Date().getTime();
        log.info("批量查询库存首次耗时:" + (l55 - l4));
        if (Objects.nonNull(forecastAnalysisQueryInventory)) {
            availableInventoryQueryList.addAll(forecastAnalysisQueryInventory.getResult());
            int total = forecastAnalysisQueryInventory.getTotal();
            if (total > 1000) {
                int totalPage = total / 1000;
                if (total % 1000 > 0) {
                    totalPage++;
                }
                for (int i = 1; i < totalPage; i++) {
                    analysisQueryInventoryRequest.setStart(i * 1000);
                    Result<List<ForecastAnalysisInventoryRequest>> pageResult =
                        crUnifiedInventoryService.forecastAnalysisQueryInventory(analysisQueryInventoryRequest);
                    if (Objects.nonNull(pageResult) && CollectionUtils.isNotEmpty(pageResult.getResult())) {
                        availableInventoryQueryList.addAll(pageResult.getResult());
                    }
                    log.info("批量查询库存" + i + "次耗时:" + ((new Date()).getTime() - l4));
                }
            }
        }

        for (ForecastAnalysisInventoryRequest analysisInventoryRequest : availableInventoryQueryList) {
            String inventoryKey = String.format("%s-%s", analysisInventoryRequest.getWarehouseAreaId(),
                analysisInventoryRequest.getGoodsId());
            inventoryMap.put(inventoryKey, analysisInventoryRequest.getAvailableQuantity());
        }

        long l5 = new Date().getTime();
        log.info("批量查询库存耗时:" + (l5 - l4));

        List<QueryForecastLineResponse> responses = Lists.newArrayList();
        for (ForecastOrderLineIndex forecastOrderLineIndex : forecastOrderLineIndices) {
            QueryForecastLineResponse queryForecastLineResponse = ForecastOrderRepositoryConverter
                .toQueryForecastLineResponse(forecastOrderLineIndex);
            responses.add(queryForecastLineResponse);

            DailyInventoryLine dailyInventoryLine = getDailyInventoryByCache(forecastOrderLineIndex);
            if (dailyInventoryLine != null) {
                queryForecastLineResponse.getFeatures().put("allotQuantity",
                    trimEndZeroOfBigDecimal(new BigDecimal(dailyInventoryLine.getDistributeQuantity())));
                queryForecastLineResponse.getFeatures().put("allotReaminQuantity",
                    trimEndZeroOfBigDecimal(new BigDecimal(dailyInventoryLine.getRemainQuantity())));
                queryForecastLineResponse.getFeatures().put("allotUsedQuantity",
                    trimEndZeroOfBigDecimal(new BigDecimal(dailyInventoryLine.getSubstractQuantity())));
            }

            if (Objects.nonNull(forecastOrderLineIndex.getMainWareHouseCode())) {
                Double convert = StringUtils.isEmpty(forecastOrderLineIndex.getSubUnitConvert()) ? 1D
                    : Double.parseDouble(forecastOrderLineIndex.getSubUnitConvert());
                // 查询可用库存
                String inventoryKey = String.format("%s-%s", forecastOrderLineIndex.getMainWareHouseCode(),
                    forecastOrderLineIndex.getSubScItemId());
                String availableInventory = Optional.ofNullable(inventoryMap.get(inventoryKey)).orElse("0");
                //库存数量解析去除末尾的0值
                queryForecastLineResponse.setAvailableInventory(
                        trimEndZeroOfBigDecimal(new BigDecimal(availableInventory).setScale(3, RoundingMode.FLOOR)));

                // 当天累计提报量
                String statKey = String.format("%s-%s", forecastOrderLineIndex.getSubScItemId(),
                    forecastOrderLineIndex.getMainOrganizationCode());
                Integer cumulativeQuantityOfForecastReports = Optional.ofNullable(
                    statMap.get(REPORTED_QUANTITY).get(statKey)).orElse(0);

                queryForecastLineResponse.setCumulativeQuantityOfForecastReports(cumulativeQuantityOfForecastReports);
                // 当天累计剩余回复差量
                Integer cumulativeQuantityOfForecastRemain = Optional.ofNullable(
                    statMap.get(REMAIN_QUANTITY).get(statKey)).orElse(0);
                double cumulativeQuantityOfForecastRemainDouble = cumulativeQuantityOfForecastRemain / convert;
                //                queryForecastLineResponse.setCumulativeQuantityOfForecastReports
                //                (cumulativeQuantityOfForecastRemain);

                // 可用库存 -提报数
                double availableInventoryOfForecast = new BigDecimal(availableInventory).subtract(
                    new BigDecimal(cumulativeQuantityOfForecastRemainDouble)).doubleValue();
                queryForecastLineResponse.setAvailableInventoryOfForecast(trimEndZeroOfBigDecimal(
                    BigDecimal.valueOf(availableInventoryOfForecast).setScale(3, RoundingMode.FLOOR)).toString());
            }

            //预计回复常规总额金额
            queryForecastLineResponse.setExpectReplyUnitPriceTotalAmount(
                compute(queryForecastLineResponse.getPredictReplyAmount(),
                    queryForecastLineResponse.getUnitPrice()));
            //预计回复活动价总额金额
            queryForecastLineResponse.setExpectReplyActivityPriceTotalAmount(
                compute(queryForecastLineResponse.getPredictReplyAmount(),
                    queryForecastLineResponse.getActivityPrice()));
        }

        long l6 = new Date().getTime();
        log.info("循环计算耗时:" + (l6 - l5));
        List<QueryForecastLineResponse> queryForecastLineResponses = gmtCreateOrderAsc(responses, oriLimit > 200);
        long l7 = new Date().getTime();
        log.info("排序耗时:" + (l7 - l6));

        return Result.listSuccess(queryForecastLineResponses, forecastOrderLineIndicesResult.getTotal());
    }

    @Override
    public DailyInventoryLine getDailyInventoryByCache(ForecastOrderLineIndex forecastOrderLineIndex) {

        Map<String, Object> features = JSONObject.parseObject(forecastOrderLineIndex.getSubFeatures());
        if (MapUtils.isEmpty(features) || Objects.isNull(
            features.get(ForecastConstants.DISINTEGRATION_ALLOT_LINE_ID))) {
            return null;
        }
        String cacheKey = ForecastConstants.DISINTEGRATION_ALLOT_CATCH_ + features.get(
            ForecastConstants.DISINTEGRATION_ALLOT_LINE_ID);

        DailyInventoryLine resp = dailyInventoryCache.getIfPresent(cacheKey);
        if (resp == null) {
            List<DailyInventoryLine> dailyInventory = getBelongDailyInventoryList(
                Lists.newArrayList(features.get(ForecastConstants.DISINTEGRATION_ALLOT_LINE_ID).toString()));
            if (CollectionUtils.isNotEmpty(dailyInventory)) {
                resp = dailyInventory.get(0);
            }
            if (resp != null) {
                dailyInventoryCache.put(cacheKey, resp);
            }
        }
        return resp;
    }

    //批量获取每日库存数据，并缓存下来
    private List<DailyInventoryLine> getBelongDailyInventoryList(List<String> request) {
        if (CollectionUtils.isEmpty(request)) {
            return new ArrayList<>();
        }
        QueryDailyAllotOrderLine queryDailyAllotOrderLine = new QueryDailyAllotOrderLine();
        queryDailyAllotOrderLine.setAllotLineIdList(request);
        Result<List<DailyInventoryLine>> dailys = inventoryAllotQueryService.queryAllotOrderLineById(
            queryDailyAllotOrderLine);
        if (dailys != null && CollectionUtils.isNotEmpty(dailys.getResult())) {
            dailys.getResult().forEach(dailyInventoryLine -> {
                dailyInventoryCache.put(ForecastConstants.DISINTEGRATION_ALLOT_CATCH_ + dailyInventoryLine.getLineId(),
                    dailyInventoryLine);
            });
            return dailys.getResult();
        }
        return new ArrayList<>();
    }

    @Override
    public QueryResolveInventoryResponse getInventoryByCache(ForecastOrderLineIndex forecastOrderLineIndex) {

        String subScItemId = forecastOrderLineIndex.getSubScItemId();
        String mainChannelCode = forecastOrderLineIndex.getMainChannelCode();
        String mainDepartmentCode = forecastOrderLineIndex.getMainDepartmentCode();
        String mainOrganizationCode = forecastOrderLineIndex.getMainOrganizationCode();
        String mainSaleChannelCode = forecastOrderLineIndex.getMainSaleChannelCode();
        String mainSalesmanCode = forecastOrderLineIndex.getMainSalesmanId();

        String cacheKey = String.format("%s-%s-%s-%s-%s-%s", mainOrganizationCode, mainChannelCode, mainDepartmentCode,
            mainSaleChannelCode, mainSalesmanCode, subScItemId);

        QueryResolveInventoryResponse resp = inventoryCache.getIfPresent(cacheKey);
        if (resp == null) {
            resp = getAccumulateQuantityOfForecast(forecastOrderLineIndex);
            if (resp != null) {
                inventoryCache.put(cacheKey, resp);
            } else {
                inventoryCache.put(cacheKey, new QueryResolveInventoryResponse());
            }
        }
        return resp;
    }

    @Override
    public ForecastOrderLineIndex getForecastOrderLineIndex(ForecastOrderLineSDO forecastOrderLineSDO) {
        SearchForecastOrderRequest pageQueryForecastRequest = new SearchForecastOrderRequest();
        pageQueryForecastRequest.setSubLineBizId(Lists.newArrayList(forecastOrderLineSDO.getId() + ""));
        pageQueryForecastRequest.setStart(0);
        pageQueryForecastRequest.setLimit(1);
        Result<List<ForecastOrderLineIndex>> resp = forecastOrderLineIndexService.queryForecastOrderLineByEs(
            pageQueryForecastRequest);
        if (resp != null && CollectionUtils.isNotEmpty(resp.getResult())) {
            return resp.getResult().get(0);
        }
        return null;
    }

    @NotNull
    //当天累计剩余回复数量
    private Map<String, Map<String, Integer>> statTodayForecastOrder(Set<String> organizationCodeList) {
        if (CollectionUtils.isEmpty(organizationCodeList)) {
            return Maps.newConcurrentMap();
        }
        Map<String, Map<String, Integer>> statics = new HashMap<>();
        //当天累计提报数量
        Map<String, Integer> statMap = Maps.newConcurrentMap();
        //当天累计剩余回复数量
        Map<String, Integer> statRemainMap = Maps.newConcurrentMap();
        SearchForecastOrderRequest queryTodayForecastRequest = new SearchForecastOrderRequest();
        queryTodayForecastRequest.setLimit(100000);
        queryTodayForecastRequest.setValidStartDate(DateUtils.getFirstTime(new Date()));
        queryTodayForecastRequest.setValidEndDate(DateUtils.getLatestTime(new Date()));
        queryTodayForecastRequest.setOrganizationCodeList(Lists.newArrayList(organizationCodeList));
        // 统计当日 待回复，部分回复， 已完成的预报单
        queryTodayForecastRequest.setDetailStatusList(Lists.newArrayList(2, 3, 4));
        queryTodayForecastRequest.setMainStatusList(Lists.newArrayList(2, 3, 4));
        Result<List<ForecastOrderLineIndex>> forecastOrderLineIndicesResult = queryForecastOrderLines(
            queryTodayForecastRequest);
        List<ForecastOrderLineIndex> forecastOrderLineIndices = forecastOrderLineIndicesResult.getResult();
        for (ForecastOrderLineIndex todayForecastOrderLineIndex : forecastOrderLineIndices) {
            if (StringUtils.isNotBlank(todayForecastOrderLineIndex.getSubRefuseReasonCode())) {
                continue;
            }

            String scItemId = todayForecastOrderLineIndex.getSubScItemId();
            String orgCode = todayForecastOrderLineIndex.getMainOrganizationCode();

            long replyQuantity = todayForecastOrderLineIndex.getSubActualTotalReplyAmount() == null ? 0L
                : todayForecastOrderLineIndex.getSubActualTotalReplyAmount();
            long quantityLong = StringUtils.isEmpty(todayForecastOrderLineIndex.getSubQuantity()) ? 0L : Long.parseLong(
                todayForecastOrderLineIndex.getSubQuantity());

            String key = String.format("%s-%s", scItemId, orgCode);
            int remainQuantity = (int)(quantityLong -replyQuantity);
            if (statMap.containsKey(key)) {
                statMap.put(key, statMap.get(key) + (int) quantityLong);
                statRemainMap.put(key, statRemainMap.get(key) + remainQuantity);
            } else {
                statMap.put(key, (int) quantityLong);
                statRemainMap.put(key, remainQuantity);
            }
        }
        statics.put(REPORTED_QUANTITY, statMap);
        statics.put(REMAIN_QUANTITY, statRemainMap);
        return statics;
    }

    public static void main(String[] args) {
        Integer s = new BigDecimal("30").subtract(new BigDecimal("2.00")).setScale(0, RoundingMode.HALF_UP).intValue();
        System.out.println(s);
        Long a = 10000L;
        Long b = 100L;

        int i = a.intValue() - b.intValue();

        System.out.println(a.intValue());
        System.out.println(b.intValue());
    }

    private Result<List<ForecastOrderLineIndex>> forecastOrderLineDemoteEs(SearchForecastOrderRequest request){
        boolean needUseMainCondition = Objects.isNull(request.getValidStartDate()) && Objects.isNull(request.getValidEndDate())
                && StringUtils.isBlank(request.getCreatorId()) && CollectionUtils.isEmpty(request.getOrganizationCodeList())
                && StringUtils.isBlank(request.getCustomerCode()) && CollectionUtils.isEmpty(request.getCustomerCodeList())
                && CollectionUtils.isEmpty(request.getOrderTypeList()) && StringUtils.isBlank(request.getReceiveAddressCode())
                && CollectionUtils.isEmpty(request.getReceiveAddressCodeList()) && CollectionUtils.isEmpty(request.getDepartmentCodeList())
                && StringUtils.isBlank(request.getCreatorName()) && StringUtils.isBlank(request.getCustomerReferenceNo())
                && Objects.isNull(request.getCustomerExpectStartDate()) && Objects.isNull(request.getCustomerExpectEndDate())
                && StringUtils.isBlank(request.getModifierName()) && StringUtils.isBlank(request.getCreatorId())
                && CollectionUtils.isEmpty(request.getMainStatusList()) && CollectionUtils.isEmpty(request.getProductGroupCodeList())
                && CollectionUtils.isEmpty(request.getSaleChannelCodeList()) && CollectionUtils.isEmpty(request.getDocReasonList())
                && StringUtils.isEmpty(request.getRemark()) && StringUtils.isEmpty(request.getWareHouseCode())
                && CollectionUtils.isEmpty(request.getWareHouseCodes()) && CollectionUtils.isEmpty(request.getTransportModeCodeList())
                && StringUtils.isEmpty(request.getContact()) && StringUtils.isEmpty(request.getContactPhone())
                && CollectionUtils.isEmpty(request.getChannelCodeList()) && StringUtils.isEmpty(request.getSalesmanCode())
                && Objects.isNull(request.getGmtStartCreate()) && Objects.isNull(request.getGmtEndCreate())
                && StringUtils.isBlank(request.getMainOrderBizId());

        if (needUseMainCondition){
            return forecastOrderLineService.queryForecastOrderLineForDemoteESMainless(request);
        }
        return forecastOrderLineService.queryForecastOrderLineForDemoteES(request);
    }

    @FacadeInvoker("查询预报子订单列表降级走DB")
    public Result<List<ForecastOrderLineIndex>> queryForecastOrderLinesByEsDegrade(
        SearchForecastOrderRequest pageQueryForecastRequest) {
        // 分页查询
        if (pageQueryForecastRequest.getStart() != null && pageQueryForecastRequest.getLimit() != null
                && pageQueryForecastRequest.getLimit() <= 200) {
            Result<List<ForecastOrderLineIndex>> listResult = forecastOrderLineDemoteEs(pageQueryForecastRequest);
            if (listResult == null || listResult.getTotal() == 0) {
                return Result.success(Lists.newArrayList());
            }
            // 聚合预报主单数据
            aggregationForecastMainOrderInfo(listResult);
            return listResult;
        }


        /*
         * 查全量时，limit最大值为2000
         * limit含义
         * 获取全量数据
         * 页面上查询分页参数最大值在200，因此若limit小于等于200，则认为被分页查询
         * 如果limit大于200认为需要获取全量数据，因此设置分页最多查询200
         */
        int limit = 200;
        pageQueryForecastRequest.setStart(0);
        pageQueryForecastRequest.setLimit(limit);
        Result<List<ForecastOrderLineIndex>> listResult = forecastOrderLineDemoteEs(
            pageQueryForecastRequest);
        if (listResult == null || listResult.getTotal() == 0) {
            return Result.success(Lists.newArrayList());
        }
        int total = listResult.getTotal();
        if (total > limit) {
            // 通过传参控制下数据量（最多查询2000条）
            total = total > pageQueryForecastRequest.getLimit() ? pageQueryForecastRequest.getLimit() : total;
            // 并行获取所有页的数据
            List<Future<List<ForecastOrderLineIndex>>> collect = Lists.newArrayList();
            List<ForecastOrderLineIndex> forecastOrderLineIndices = Lists.newArrayList();
            int totalPage = total % limit == 0 ? total / limit : total / limit + 1;
            for (int i = 0; i < totalPage; i++) {
                int finalI = i;
                CompletableFuture<List<ForecastOrderLineIndex>> future = CompletableFuture.supplyAsync(() -> {
                    SearchForecastOrderRequest tmpReq = new SearchForecastOrderRequest();
                    BeanUtils.copyProperties(pageQueryForecastRequest, tmpReq);
                    tmpReq.setStart(finalI * limit);
                    tmpReq.setLimit(limit);
                    Result<List<ForecastOrderLineIndex>> tmpResult = forecastOrderLineService
                        .queryForecastOrderLineForDemoteES(tmpReq);
                    if (tmpResult != null && CollectionUtils.isNotEmpty(tmpResult.getResult())) {
                        return tmpResult.getResult();
                    }
                    return Lists.newArrayList();
                }, scItemsQueryTaskExecutor);

                collect.add(future);
            }
            for (Future<List<ForecastOrderLineIndex>> listFuture : collect) {
                try {
                    forecastOrderLineIndices.addAll(listFuture.get());
                } catch (Exception e) {
                    log.error("多线程查询销售子单异常:",e);
                }
            }
            listResult.setResult(forecastOrderLineIndices);
        }
        // 聚合预报主单数据
        aggregationForecastMainOrderInfo(listResult);
        return listResult;
    }

    private void aggregationForecastMainOrderInfo(Result<List<ForecastOrderLineIndex>> listResult) {

        BatchQueryByIdsRequest batchQueryByIdsRequest=new BatchQueryByIdsRequest();
        List<String> mainOrderIdsList=Nullable.stream(listResult.getResult()).map(ForecastOrderLineIndex::getSubMainOrderId)
                .distinct().collect(Collectors.toList());
        batchQueryByIdsRequest.setIds(mainOrderIdsList);
        batchQueryByIdsRequest.setLimit(10000);
        //
        Result<List<ForecastOrder>> mainOrders = forecastOrderService.batchQueryByIds(batchQueryByIdsRequest);
        if (mainOrders != null && CollectionUtils.isNotEmpty(mainOrders.getResult())) {
            Map<String, ForecastOrder> mainOrderMap = mainOrders.getResult().stream().collect(
                    Collectors.toMap(x->x.getId().toString(), x -> x, (key1, key2) -> key2));
            listResult.getResult().forEach(x ->
            {
                ForecastOrder mainOrder = mainOrderMap.get(x.getSubMainOrderId());
                if (mainOrder != null) {
                    aggregationForecastMainInfo(x, mainOrder);
                }
            });
        }
    }

    private void aggregationForecastMainInfo(ForecastOrderLineIndex lineIndex, ForecastOrder mainOrder) {
        lineIndex.setMainWareHouseName(mainOrder.getWareHouseName());
        lineIndex.setMainWareHouseCode(mainOrder.getWareHouseCode());
        lineIndex.setMainModifierName(mainOrder.getModifierName());
        lineIndex.setMainModifierId(mainOrder.getModifierId());
        lineIndex.setMainSalesmanId(mainOrder.getSalesmanId());
        lineIndex.setMainSalesmanName(mainOrder.getSalesmanName());
        lineIndex.setMainBusinessCode(mainOrder.getBusinessCode());
        lineIndex.setMainUpdater(mainOrder.getUpdater());
        lineIndex.setMainOrganizationCode(mainOrder.getOrganizationCode());
        lineIndex.setMainOrganizationName(mainOrder.getOrganizationName());
        if(mainOrder.getCustomerExpectTDate()!=null) {
            lineIndex.setMainCustomerExpectTDate(mainOrder.getCustomerExpectTDate().getTime());
        }
        lineIndex.setMainSaleChannelName(mainOrder.getSaleChannelName());
        lineIndex.setMainSaleChannelCode(mainOrder.getSaleChannelCode());
        lineIndex.setMainAddRemark(mainOrder.getAddRemark());
        lineIndex.setMainCreditBalance(mainOrder.getCreditBalance());
        if(mainOrder.getStatus()!=null) {
            lineIndex.setMainStatus(mainOrder.getStatus().longValue());
        }

        lineIndex.setMainCustomerReferenceNo(mainOrder.getCustomerReferenceNo());
        lineIndex.setMainReceiveAddressCode(mainOrder.getReceiveAddressCode());
        lineIndex.setMainReceiveDetailAddress(mainOrder.getReceiveDetailAddress());
        lineIndex.setMainRemark(mainOrder.getRemark());
        lineIndex.setMainCustomerCode(mainOrder.getCustomerCode());
        lineIndex.setMainCustomerName(mainOrder.getCustomerName());
        lineIndex.setMainProductGroupCode(mainOrder.getProductGroupCode());
        lineIndex.setMainProductGroupName(mainOrder.getProductGroupName());
        lineIndex.setMainCreator(mainOrder.getCreator());
        lineIndex.setMainCreatorId(mainOrder.getCreatorId());
        lineIndex.setMainCreatorName(mainOrder.getCreatorName());
        lineIndex.setMainTransportModeCode(mainOrder.getTransportModeCode());
        lineIndex.setMainTransportModeName(mainOrder.getTransportModeName());
        lineIndex.setMainBizCode(mainOrder.getBizCode());
        lineIndex.setMainDepartmentCode(mainOrder.getDepartmentCode());
        lineIndex.setMainDepartmentName(mainOrder.getDepartmentName());
        lineIndex.setMainContact(mainOrder.getContact());
        lineIndex.setMainContactPhone(mainOrder.getContactPhone());
        lineIndex.setMainChannelCode(mainOrder.getChannelCode());
        lineIndex.setMainChannelName(mainOrder.getChannelName());
        if(mainOrder.getGmtCreate()!=null){
            lineIndex.setMainGmtCreate(mainOrder.getGmtCreate().getTime());
        }
        if(mainOrder.getGmtModified()!=null) {
            lineIndex.setMainGmtModified(mainOrder.getGmtModified().getTime());
        }
        lineIndex.setMainOrderBizId(mainOrder.getOrderBizId());
        lineIndex.setMainBisUnitCode(mainOrder.getBisUnitCode());
        if(mainOrder.getVaildBeginTime()!=null){
            lineIndex.setMainVaildBeginTime(mainOrder.getVaildBeginTime().getTime());
        }
        lineIndex.setMainOrderType(mainOrder.getOrderType());

        String subFeatures = lineIndex.getSubFeatures();
        if (StringUtils.isNotBlank(subFeatures)){
            JSONObject subFeatureJson = JSONObject.parseObject(subFeatures);
            //活动单价备注
            lineIndex.setSubActivityPriceRemark(subFeatureJson.getString(ForecastConstants.ACTIVITY_PRICE_REMARK));
        }
    }

    @RepositoryInvoker
    private Result<List<ForecastOrderLineIndex>> queryForecastOrderLines(
        SearchForecastOrderRequest pageQueryForecastRequest) {
        if (esDegradeService.getEsDegradeValue()!=null&&esDegradeService.getEsDegradeValue().getResult()) {
            return queryForecastOrderLinesByEsDegrade(pageQueryForecastRequest);
        }
        // 分页查询
        if (pageQueryForecastRequest.getStart() != null && pageQueryForecastRequest.getLimit() != null
            && pageQueryForecastRequest.getLimit() <= 200) {
            return forecastOrderLineIndexService.queryForecastOrderLineByEs(pageQueryForecastRequest);
        }
        // 查全量
        Integer oriLimit = pageQueryForecastRequest.getLimit();
        // 1.获取总数量
        int total = 0;
        int limit = 200;
        pageQueryForecastRequest.setStart(0);
        pageQueryForecastRequest.setLimit(limit);
        Result<List<ForecastOrderLineIndex>> listResult = forecastOrderLineIndexService.queryForecastOrderLineByEs(
            pageQueryForecastRequest);
        if (listResult != null) {
            total = listResult.getTotal();
        }

        if (total <= limit) {
            return listResult;
        }

        // 通过传参控制下数据量
        total = total > oriLimit ? oriLimit : total;

        // 并行获取所有页的数据
        List<Future<List<ForecastOrderLineIndex>>> collect = Lists.newArrayList();
        List<ForecastOrderLineIndex> forecastOrderLineIndices = Lists.newArrayList();
        int totalPage = total % limit == 0 ? total / limit : total / limit + 1;
        for (int i = 0; i < totalPage; i++) {
            int finalI = i;
            CompletableFuture<List<ForecastOrderLineIndex>> future = CompletableFuture.supplyAsync(() -> {
                SearchForecastOrderRequest tmpReq = new SearchForecastOrderRequest();
                BeanUtils.copyProperties(pageQueryForecastRequest, tmpReq);
                tmpReq.setStart(finalI * limit);
                tmpReq.setLimit(limit);
                Result<List<ForecastOrderLineIndex>> tmpResult = forecastOrderLineIndexService
                    .queryForecastOrderLineByEs(tmpReq);
                if (tmpResult != null && CollectionUtils.isNotEmpty(tmpResult.getResult())) {
                    return tmpResult.getResult();
                }
                return Lists.newArrayList();
            }, scItemsQueryTaskExecutor);

            collect.add(future);
        }

        for (Future<List<ForecastOrderLineIndex>> listFuture : collect) {
            try {
                forecastOrderLineIndices.addAll(listFuture.get());
            } catch (Exception e) {
                // ignore
            }
        }

        listResult.setResult(forecastOrderLineIndices);
        return listResult;
    }

    private Long getForecastOrderImportIndex(QueryForecastLineResponse o1) {
        if (o1 == null || MapUtils.isEmpty(o1.getFeatures())) {
            return Long.MAX_VALUE;
        }

        Object importIndex = o1.getFeatures().getOrDefault(ForecastConstants.FORECAST_ORDER_IMPORT_INDEX, "");
        String indexNum = StringUtils.replace(importIndex.toString(), "_", "");
        return NumberUtils.toLong(indexNum, Long.MAX_VALUE);
    }

    private QueryResolveInventoryResponse getAccumulateQuantityOfForecast(
        ForecastOrderLineIndex forecastOrderLineIndex) {
        String subScItemId = forecastOrderLineIndex.getSubScItemId();
        BatchQueryAllotRequest batchQueryAllotRequest = new BatchQueryAllotRequest();
        batchQueryAllotRequest.setChannelCode(forecastOrderLineIndex.getMainChannelCode());
        batchQueryAllotRequest.setDepartmentCode(forecastOrderLineIndex.getMainDepartmentCode());
        batchQueryAllotRequest.setOrganizationCode(forecastOrderLineIndex.getMainOrganizationCode());
        batchQueryAllotRequest.setSaleChannelCode(forecastOrderLineIndex.getMainSaleChannelCode());
        batchQueryAllotRequest.setSalesmanCode(forecastOrderLineIndex.getMainSalesmanId());
        batchQueryAllotRequest.setScItemList(Arrays.asList(subScItemId));
        Result<QueryResolveInventoryResponse> result = inventoryAllotQueryService.batchQueryAllot(
            batchQueryAllotRequest);
        if (Objects.nonNull(result) && Objects.nonNull(result.getResult())
            && Objects.nonNull(result.getResult().getDailyInventoryMap())
            && Objects.nonNull(result.getResult().getDailyInventoryMap().get(subScItemId))) {
            return result.getResult();
        }
        return null;
    }

    public List<QueryForecastLineResponse> gmtCreateOrderAsc(List<QueryForecastLineResponse> forecastList,
        boolean importSort) {
        //        if(importSort) {
        //            forecastList.sort(Comparator.comparing(this::getForecastOrderImportIndex));
        //        } else {
        return forecastList.stream()
                .filter(Objects::nonNull)
                .filter(line -> Objects.nonNull(line.getOrderBizId()))
                .sorted(Comparator.comparing(QueryForecastLineResponse::getOrderBizId))
                .collect(Collectors.toList());
        //        }
        //        return forecastList;
    }

    private Integer getPredictReplyAmount(ForecastOrderSDO forecastOrderSDO,
        ForecastOrderLineSDO forecastOrderLineSDO) {
        return 100;
    }

    public Long getPrice(ForecastOrderSDO forecastOrderSDO, ForecastOrderLineSDO forecastOrderLineSDO) {
        //一 获取价格
        PriceQueryRequest priceQueryRequest = new PriceQueryRequest();
        List<DimensionPropertyInfoRequest> DimensionPropertyInfoList = new ArrayList<>();
        DimensionPropertyInfoRequest dimensionPropertyInfoRequest = new DimensionPropertyInfoRequest();
        dimensionPropertyInfoRequest.setPriceTypeId("ZP01");//价格类型
        dimensionPropertyInfoRequest.setPriceUseDate(new Date());//价格使用时间
        //场地的信息
        PlaceInfoRequest placeInfoRequest = PlaceInfoRequest.builder()
            .orgSalesOrganizationCode(forecastOrderSDO.getOrganizationCode())//销售组织
            //                    .orgSalesOrganizationCode("6140")//销售组织
            .channelCode(forecastOrderSDO.getChannelCode())//业务渠道code
            //                    .salesUnitCode(forecastOrderLineSDO.getSaleUnit())//销售单位code
            .salesUnitCode("GUA")//销售单位code
            .salesArea("")//销售地区编码
            .factoryCode("")//工厂编码
            .departmentCode(forecastOrderSDO.getDepartmentCode())//销售部门
            .priceArea("")//定价区域
            .build();
        dimensionPropertyInfoRequest.setPlaceInfoRequest(placeInfoRequest);
        //货的信息
        MaterialInfoRequest materialInfoRequest = new MaterialInfoRequest();
        materialInfoRequest.setMaterialCode(forecastOrderLineSDO.getScItemId());//货品编码（ SAP物料编码）
        //            materialInfoRequest.setScItemGroupCode(forecastOrderSDO.getProductGroupCode());//产品组编码
        materialInfoRequest.setScItemGroupCode("11");//产品组编码 货品组
        dimensionPropertyInfoRequest.setMaterialInfoRequest(materialInfoRequest);
        // 人的信息
        HumanInfoRequest humanInfoRequest = new HumanInfoRequest();
        humanInfoRequest.setCustomerCode(forecastOrderSDO.getCustomerCode());//客户编码
        humanInfoRequest.setCustomerSaleAddressCode(forecastOrderSDO.getWareHouseCode());//售达方编码 客户编码（SAP售达方编码）
        humanInfoRequest.setCustomerGroup("");//客户组
        humanInfoRequest.setCustomerSendAddressCode(forecastOrderSDO.getReceiveAddressCode());//客户收货地址编码（SAP 送达方编码）
        //                humanInfoRequest.setCustomerSendAddressCode("3730300301");//客户收货地址编码（SAP 送达方编码）
        humanInfoRequest.setPriceListCode("");//价目清单编码 (从客户信息上取)
        dimensionPropertyInfoRequest.setHumanInfoRequest(humanInfoRequest);
        //添加维度
        DimensionPropertyInfoList.add(dimensionPropertyInfoRequest);
        priceQueryRequest.setDimensionPropertyInfoRequestList(DimensionPropertyInfoList);
        Result<PriceQueryResponse> priceQueryResponseResult = priceQueryService.batchQueryPrice(priceQueryRequest);
        if (priceQueryResponseResult.isSuccess() || priceQueryResponseResult.getResult() == null) {
            return 0L;
        }
        List<ItemPriceResponse> itemPriceResponseList = priceQueryResponseResult.getResult().getItemPriceResponseList();
        ItemPriceResponse itemPriceResponse = itemPriceResponseList.get(0);
        Long moneyAmout = itemPriceResponse.getMoneyAmout();
        return moneyAmout;
    }

    @Override
    public ForecastOrderSDO queryByOrderId(ForecastOrderSDO forecastOrderSDO) {
        ForecastOrderLine forecastOrderLineLoadListRequest = new ForecastOrderLine();
        forecastOrderLineLoadListRequest.setMainOrderId(forecastOrderSDO.getId());
        Result<List<ForecastOrderLine>> listResult = forecastOrderLineService.loadForecastOrderLineList(
            forecastOrderLineLoadListRequest);
        List<ForecastOrderLine> forecastOrderLines = listResult.getResult();
        List<ForecastOrderLineSDO> forecastOrderLineSDOList = new ArrayList<>();
        for (Object obj : forecastOrderLines) {
            ForecastOrderLine forecastOrderLine = JSONObject.parseObject(JSONObject.toJSONString(obj),
                ForecastOrderLine.class);
            ForecastOrderLineSDO forecastOrderLineSDO = new ForecastOrderLineSDO();
            forecastOrderLineSDO.setId(forecastOrderLine.getId());
            forecastOrderLineSDO.setStatus(forecastOrderLine.getStatus());
            forecastOrderLineSDO.setFeatures(JSONObject.parseObject(forecastOrderLine.getFeatures()));
            forecastOrderLineSDO.setQuantity(forecastOrderLine.getQuantity());
            forecastOrderLineSDO.setSerialNumber(forecastOrderLine.getSerialNumber());
            forecastOrderLineSDO.setScItemId(forecastOrderLine.getScItemId());
            forecastOrderLineSDO.setUnitConvert(forecastOrderLine.getUnitConvert());
            forecastOrderLineSDO.setGoodsCode(forecastOrderLine.getScItemOutCode());
            forecastOrderLineSDO.setActivityCode(forecastOrderLine.getActivityCode());
            //活动项目号
            String features = forecastOrderLine.getFeatures();
            if (StringUtils.isNotBlank(features)){
                JSONObject jsonObject = JSONObject.parseObject(features);
                String activityNumber = jsonObject.getString(ForecastConstants.ACTIVITY_NUMBER);
                forecastOrderLineSDO.setActivityNumber(activityNumber);
            }
            forecastOrderLineSDOList.add(forecastOrderLineSDO);
        }
        forecastOrderSDO.setForecastOrderLineSDOList(forecastOrderLineSDOList);

        return forecastOrderSDO;
    }

    /**
     * 根据处理状态查询子订单
     *
     * @param dealStatus
     * @return
     */
    @Override
    public PageResult<List<ForecastOrderLineSDO>> queryListByDealStatus(List<Integer> dealStatus) {
        LoadListByDealStatusRequest loadListByDealStatusRequest = new LoadListByDealStatusRequest();
        loadListByDealStatusRequest.setDealStatusList(dealStatus);
        LoadListByDealStatusResponse batchLoadListResponse = new LoadListByDealStatusResponse();
        try {
            batchLoadListResponse = forecastOrderLineService.loadListByDealStatus(loadListByDealStatusRequest);
        } catch (Exception e) {
            log.error("查询异常", e);
        }
        List<ForecastOrderLineSDO> collect = Nullable.stream(batchLoadListResponse.getResult()).map(
            ForecastOrderRepositoryConverter::toForecastOrderLineSDO).collect(Collectors.toList());
        List<ForecastOrderLineSDO> collect1 = Nullable.stream(collect).sorted(
            Comparator.comparing(ForecastOrderLineSDO::getId).reversed()).collect(Collectors.toList());
        return PageResult.of(collect1, batchLoadListResponse.getResult().size());
    }

    //库存数量解析去除末尾的0值
    private String trimEndZeroOfBigDecimal(BigDecimal bigDecimal) {
        String val = "";
        if (bigDecimal == null) {
            return val;
        } else {
            val = String.valueOf(bigDecimal);
        }
        if (val.indexOf(".") > 0) {
            // 去掉后面无用的零
            val = val.replaceAll("0+?$", "");
            // 如小数点后面全是零则去掉小数点
            val = val.replaceAll("[.]$", "");
        }
        return val;
    }

    @Override
    public List<DealForecastOrderResponse> loadDealForecastListV2(DealForecastListRequest dealForecastListRequest) {
        List<DealForecastOrderResponse> dealForecastOrderResponses = new CopyOnWriteArrayList<>();
        //nowIds是主单id，新版本v2不用该字段
        //ids页面选中的子单id
        List<String> orderLineIds = dealForecastListRequest.getIds().stream().map(String::valueOf).collect(
            Collectors.toList());

        //根据当前日期的单据主单Id 查询出所有的子单
        //        List<String> nowLineIds = dealForecastListRequest.getNowLineIds();
        // 货品按照仓库进行分组
        Map<String, Set<String>> itemWarehouseGroup = Maps.newHashMap();
        SearchForecastOrderRequest queryTodayForecastRequest = new SearchForecastOrderRequest();
        queryTodayForecastRequest.setLimit(100000);
        queryTodayForecastRequest.setGmtStartCreate(DateUtils.getFirstTime(new Date()));
        queryTodayForecastRequest.setGmtEndCreate(DateUtils.getLatestTime(new Date()));
        // 统计当日 待回复，部分回复， 已完成的预报单
        queryTodayForecastRequest.setDetailStatusList(Lists.newArrayList(2, 3, 4));
        Result<List<ForecastOrderLineIndex>> forecastOrderLineIndicesResult = queryForecastOrderLines(
            queryTodayForecastRequest);

        //当天累计剩余回复数量
        Map<String, Integer> remainReplyCntMap = Maps.newConcurrentMap();
        //        //主单IDs
        //        Set<String> mainOrderIds = Sets.newHashSet();
        //主单id/客户信贷信息
        Map<String, ForecastOrderLineIndex> mainOrderMap = Maps.newConcurrentMap();
        List<ForecastOrderLineIndex> forecastOrderLineIndices = forecastOrderLineIndicesResult.getResult();
        for (ForecastOrderLineIndex todayForecastOrderLineIndex : forecastOrderLineIndices) {
            //当天累计剩余回复数量
            String scItemId = todayForecastOrderLineIndex.getSubScItemId();
            String wareHouseAreaId = todayForecastOrderLineIndex.getMainWareHouseCode();
            long replyQuantity = todayForecastOrderLineIndex.getSubActualTotalReplyAmount() == null ? 0L
                : todayForecastOrderLineIndex.getSubActualTotalReplyAmount();
            long quantityLong = StringUtils.isEmpty(todayForecastOrderLineIndex.getSubQuantity()) ? 0L : Long.parseLong(
                todayForecastOrderLineIndex.getSubQuantity());

            String key = String.format("%s-%s", wareHouseAreaId, scItemId);
            //            int quantity = quantityLong.intValue() - replyQuantity.intValue();
            int remainQuantity = (int) quantityLong - (int) replyQuantity;
            if (remainReplyCntMap.containsKey(key)) {
                remainReplyCntMap.put(key, remainReplyCntMap.get(key) + remainQuantity);
            } else {
                remainReplyCntMap.put(key, remainQuantity);
            }
        }
        SearchForecastOrderRequest selectQuery = new SearchForecastOrderRequest();
        selectQuery.setLimit(100000);
        selectQuery.setSubLineBizId(orderLineIds);
        Result<List<ForecastOrderLineIndex>> selectedForecastOrderLines = queryForecastOrderLines(selectQuery);
        if (selectedForecastOrderLines == null || CollectionUtils.isEmpty(selectedForecastOrderLines.getResult())) {
            return dealForecastOrderResponses;
        }

        for (ForecastOrderLineIndex todayForecastOrderLineIndex : selectedForecastOrderLines.getResult()) {
            //选中的主子单
            if (!mainOrderMap.containsKey(todayForecastOrderLineIndex.getSubMainOrderId())) {
                mainOrderMap.put(todayForecastOrderLineIndex.getSubMainOrderId(), todayForecastOrderLineIndex);
            }
            // //选中的主子单 按照仓库将货品分组
            String mainWareHouseCode = todayForecastOrderLineIndex.getMainWareHouseCode();
            String subScItemId = todayForecastOrderLineIndex.getSubScItemId();

            Set<String> scItemSets = itemWarehouseGroup.get(mainWareHouseCode);
            if (scItemSets == null) {
                scItemSets = Sets.newHashSet();
                itemWarehouseGroup.put(mainWareHouseCode, scItemSets);
            }
            scItemSets.add(subScItemId);

        }

        //批量查询信贷入参
        List<CreditQueryRequest> creditQueryRequestList=new ArrayList<>();
        //销售组织ID-客户编码-业务渠道-货品组->信贷余额
        Map<String,Long> creditMap=new HashMap<>();

        ForecastOrderRepositoryConverter.buildCreditRequestList(mainOrderMap, creditQueryRequestList);
        try {
            batchQueryCreditList(creditQueryRequestList, creditMap);
        } catch (Throwable e) {
            String lastMessage = "信用检查失败";
            log.error("ForecastOrderLineAbility$check_credit_failed", e);
//            throw new Exception(lastMessage);
        }


        // 批量查询库存
        Map<String, Double> inventoryMap = Maps.newHashMap();
        Map<String, Date> inventoryDomMap = Maps.newHashMap();
        for (Map.Entry<String, Set<String>> entrySet : itemWarehouseGroup.entrySet()) {
            //获取可用库存
            List<WarehouseInventory> warehouseStockList = null;
            // es降级开关 若开关开启，需要走db降级查询 开关未开启，走原有逻辑
            GetEsDegradeValueResponse esDegradeValue = esDegradeService.getEsDegradeValue();
            if (esDegradeValue != null && esDegradeValue.getResult()){
                ForecastAnalysisQueryInventoryRequest req = ForecastAnalysisQueryInventoryRequest.builder()
                        .goodsIds(Lists.newArrayList(entrySet.getValue()))
                        .types(Lists.newArrayList(2, 3))
                        .warehouseAreaId(entrySet.getKey())
                        .build();
                warehouseStockList = Nullable.stream(unifiedInventoryService.forecastAnalysisQueryInventory(req).getResult()).map(e -> {
                    return WarehouseInventory.builder().warehouseAreaId(e.getWarehouseAreaId()).goodsId(e.getGoodsId()).availableQuantityFormat(e.getAvailableQuantity()).build();
                }).collect(Collectors.toList());

            }else{// 获取可用库存
            GetListWarehouseStockRequest getListWarehouseStockRequest = GetListWarehouseStockRequest.builder()
                .goodsIds(Lists.newArrayList(entrySet.getValue()))
                .type("1")
                .warehouseAreaId(entrySet.getKey())
                .size(entrySet.getValue().size())
                .page(1).build();

                warehouseStockList = forecastOrderQueryRepository.getListWarehouseStock(
                getListWarehouseStockRequest);
            }
            if (org.apache.commons.collections.CollectionUtils.isEmpty(warehouseStockList)) {
                continue;
            }

            for (WarehouseInventory warehouseInventory : warehouseStockList) {
                String inventoryKey = String.format("%s-%s", warehouseInventory.getWarehouseAreaId(),
                    warehouseInventory.getGoodsId());
                inventoryMap.put(inventoryKey, Double.parseDouble(warehouseInventory.getAvailableQuantityFormat()));
            }

            //获取库存dom日期
            ForecastReplyQueryInventoryDomRequest replyQueryInventoryDomRequest = ForecastReplyQueryInventoryDomRequest.builder()
                    .goodsIds(Lists.newArrayList(entrySet.getValue()))
                    .types(Lists.newArrayList(2, 3))
                    .warehouseAreaId(entrySet.getKey())
                    .build();
            Result<List<ForecastReplyInventoryResponse>> domList = unifiedInventoryService.forecastReplyQueryInventoryDom(replyQueryInventoryDomRequest);
            if (Objects.nonNull(domList)&&CollectionUtils.isNotEmpty(domList.getResult())){
                for (ForecastReplyInventoryResponse forecastReplyInventoryResponse : domList.getResult()) {
                    String inventoryKey = String.format("%s-%s", forecastReplyInventoryResponse.getWarehouseAreaId(),
                            forecastReplyInventoryResponse.getGoodsId());
                    inventoryDomMap.put(inventoryKey, forecastReplyInventoryResponse.getDomDate());

                }
            }

        }

        Map<Long, DealForecastOrderResponse> dealForecastOrderResponseMap = new ConcurrentHashMap<>();
        //        Map<Long, Integer> dealForecastOrderResponsesFutures = new ConcurrentHashMap<>();
        //        Map<Long,Integer> dealForecastOrderResponsesFutures = new ConcurrentHashMap<>();
        Map<Long, CompletableFuture<Integer>> dealForecastOrderResponsesFutures = new ConcurrentHashMap<>();
        long time = new Date().getTime();


        //查询销售子单主单ID
        List<String> mainSalesmanIds = Nullable.stream(selectedForecastOrderLines.getResult()).map(ForecastOrderLineIndex::getMainSalesmanId).collect(Collectors.toList());
        List<String> mainAddressCodes = Nullable.stream(selectedForecastOrderLines.getResult()).map(ForecastOrderLineIndex::getMainReceiveAddressCode).collect(Collectors.toList());
        QuerySaleOrderMainIdRequest querySaleOrderMainIdRequest = new QuerySaleOrderMainIdRequest();
        querySaleOrderMainIdRequest.setSalesmanIds(mainSalesmanIds);
        querySaleOrderMainIdRequest.setAddressCodes(mainAddressCodes);
        QuerySaleOrderMainIdResponse mainIds = crB2bTradeCenterService.querySaleOrderMainId(querySaleOrderMainIdRequest);
        Map<String,List<String>> mainOrderId=new HashMap<>();
        if (Objects.nonNull(mainIds)&& org.apache.commons.collections4.CollectionUtils.isNotEmpty(mainIds.getResult())){
            mainOrderId = mainIds.getResult().stream().collect(Collectors.toMap(o -> o.getSalesmanId() + "-" + o.getReceiveAddressCode() + "-" + o.getGmtCreate(), MainOrderIdResponse::getMainOrderId, (v1, v2) -> v1));
        }

        for (ForecastOrderLineIndex lineIndex : selectedForecastOrderLines.getResult()) {
            //            ForecastOrderLineIndex forecastOrderSDO = mainOrderMap.get(lineIndex.getSubMainOrderId());
            String inventoryKey = String.format("%s-%s", lineIndex.getMainWareHouseCode(), lineIndex.getSubScItemId());
            //            String remainKey = String.format("%s-%s", forecastOrderSDO.getMainWareHouseCode(),
            //            lineIndex.getSubScItemId());
            String remainKey = String.format("%s-%s", lineIndex.getMainWareHouseCode(), lineIndex.getSubScItemId());
            Integer remainCnt = remainReplyCntMap.get(remainKey);
            Double inventoryCnt = inventoryMap.get(inventoryKey);
            WeatherDomMgeSaleOrgRequest weatherDomMgeSaleOrgRequest = new WeatherDomMgeSaleOrgRequest();
            weatherDomMgeSaleOrgRequest.setSalesOrgId(lineIndex.getMainOrganizationCode());
            Result<Boolean> domMgeSaleOrg = crPlatformEnhanceService.weatherDomMgeSaleOrg(weatherDomMgeSaleOrgRequest);

            Date inventoryEarliestDom = Objects.nonNull(domMgeSaleOrg)&&domMgeSaleOrg.getResult()?inventoryDomMap.get(inventoryKey):null;
            //信贷
            String organizationCode = lineIndex.getMainOrganizationCode();
            String customerCode = lineIndex.getMainCustomerCode();
            String channelCode = lineIndex.getMainChannelCode();
            String productGroupCode = lineIndex.getMainProductGroupCode();
            String creditKey = String.format("%s-%s-%s-%s", organizationCode, customerCode, channelCode,
                productGroupCode);
            Long creditCnt = creditMap.get(creditKey);
            DealForecastOrderResponse dealForecastOrderResponse = convert2DealForecastOrderResponseByIndex(lineIndex,
                remainCnt, inventoryCnt, creditCnt,inventoryEarliestDom);
            dealForecastOrderResponses.add(dealForecastOrderResponse);
            dealForecastOrderResponseMap.put(lineIndex.getSubId(), dealForecastOrderResponse);


            //月度计划
            Map<String, List<String>> finalMainOrderId = mainOrderId;
            CompletableFuture<Integer> dealForecastOrderResponseFuture = CompletableFuture.supplyAsync(() -> {
                //计划差量
                /**
                 * 1、获取该客户的本月累计月度计划回复数量
                 * 2、计算本月销售订单的累计出库数量
                 * 3、该值=1-2
                 * 4、不可编辑
                 */
                //根据固定条件获取客户地址唯一id
                //计划量和发货数量的差量
                Date date = new Date(lineIndex.getSubGmtCreate());

                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM");
                String format = simpleDateFormat.format(date);
                Integer planDifferenceQuantity = this.getPlanDifferenceQuantity(lineIndex, finalMainOrderId);
                //                Integer planDifferenceQuantity = this.querySalesPlanTaskCount(lineIndex
                //                .getMainBisUnitCode(),lineIndex.getMainCreatorId(),lineIndex.getSubScItemId(),format);
                return planDifferenceQuantity;
            }, scItemsQueryTaskExecutor);

            //            dealForecastOrderResponsesFutures.put(lineIndex.getSubId(), planDifferenceQuantity);
            dealForecastOrderResponsesFutures.put(lineIndex.getSubId(), dealForecastOrderResponseFuture);
        }

        //        for (Map.Entry<Long, Integer> entry : dealForecastOrderResponsesFutures.entrySet()) {
        for (Map.Entry<Long, CompletableFuture<Integer>> entry : dealForecastOrderResponsesFutures.entrySet()) {
            DealForecastOrderResponse resp = dealForecastOrderResponseMap.get(entry.getKey());
            Integer planVariance = null;
            try {
                //                planVariance = entry.getValue();
                planVariance = entry.getValue().get(2, TimeUnit.SECONDS);
            } catch (Exception e) {
                log.info("获取计划差量失败", e);
            }
            resp.setPlanVariance(planVariance);
        }
        long time2 = new Date().getTime();
        log.info("查询统计销售子单耗时:"+(time2-time));
        return dealForecastOrderResponses;
    }



    private void batchQueryCreditList(List<CreditQueryRequest> creditQueryRequestList, Map<String, Long> creditMap) {
        //去重同条件信贷查询
        List<CreditQueryRequest> distinctList = creditQueryRequestList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getCustomerCode()+"-"+o.getChannelCode()+"-"+o.getInnerOrganizationCode()+"-"+o.getItemGroupCode()))), ArrayList::new));
        BatchQueryCreditListRequest batchQueryCreditListRequest = new BatchQueryCreditListRequest();
        batchQueryCreditListRequest.setRequestList(distinctList);
        Result<List<CreditInfoSDO>> batchQueryCreditList = creditQueryService.batchQueryCreditList(batchQueryCreditListRequest);

        if (Objects.nonNull(batchQueryCreditList) &&
                org.apache.commons.collections4.CollectionUtils.isNotEmpty(batchQueryCreditList.getResult())) {
            for (CreditInfoSDO creditInfoSDO : batchQueryCreditList.getResult()) {
                if (Objects.nonNull(creditInfoSDO.getBalance())) {
                    String creditKey = String.format("%s-%s-%s-%s", creditInfoSDO.getInnerOrganizationCode(),  creditInfoSDO.getCustomerCode(), creditInfoSDO.getChannelCode(),
                            creditInfoSDO.getItemGroupCode());
                    long balance = new BigDecimal(creditInfoSDO.getBalance()).multiply(new BigDecimal("100")).longValue();
                    creditMap.put(creditKey, balance);
                }
            }
        }
    }

    private Integer querySalesPlanTaskCount(String bisUnitCode, String principal, String scItemId, String planMonth) {
        PageQuerySalePlanRequest pageQuerySalePlanRequest = new PageQuerySalePlanRequest();
        pageQuerySalePlanRequest.setPlanTime(planMonth);
        pageQuerySalePlanRequest.setOrgBusinessUnitCode(bisUnitCode);
        pageQuerySalePlanRequest.setStatus(SalesPlanStatusEnum.PUBLISHED.getCode().toString());
        Result<PageResult<List<SalesPlanSDO>>> pageResultResult = salesPlanQueryService.pageQuerySalesPlanList(
            pageQuerySalePlanRequest);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(pageResultResult.getResult().getContent())) {
            return 0;
        }
        String planId = pageResultResult.getResult().getContent().get(0).getId().toString();
        QueryPlanScItemStatRequest pageQueryPlanScItemStatRequest = new QueryPlanScItemStatRequest();
        pageQueryPlanScItemStatRequest.setPlanId(Long.valueOf(planId));
        pageQueryPlanScItemStatRequest.setPoolType(String.valueOf(StatPoolTypeEnum.SC_ITEM.getPoolType()));
        pageQueryPlanScItemStatRequest.setBizIds(Lists.newArrayList(principal));
        pageQueryPlanScItemStatRequest.setBizType(SalesStatBizTypeEnum.SALESMAN.getBizType());
        pageQueryPlanScItemStatRequest.setStart(0);
        pageQueryPlanScItemStatRequest.setLimit(1000);
        pageQueryPlanScItemStatRequest.setScItemId(scItemId);
        Result<PageResult<List<SalesPlanStatScItemSDO>>> firstResult = salesPlanScItemStatQueryService
            .batchQueryPlanScItemByBizId(pageQueryPlanScItemStatRequest);

        if (Objects.isNull(firstResult) || Objects.isNull(firstResult.getResult())
            || org.apache.commons.collections4.CollectionUtils.isEmpty(firstResult.getResult().getContent())) {
            //throw new FunctionException("OTS-05-001-10-16-016");
            return 0;
        }
        List<SalesPlanStatScItemSDO> totalResult = new ArrayList<>();
        int total = firstResult.getTotal();
        if (total > 1000) {
            int page = total / 1000;
            for (int i = 0; i <= page; i++) {
                pageQueryPlanScItemStatRequest.setStart(i * 1000);
                pageQueryPlanScItemStatRequest.setLimit(1000);
                Result<PageResult<List<SalesPlanStatScItemSDO>>> resultResult = salesPlanScItemStatQueryService
                    .batchQueryPlanScItemByBizId(pageQueryPlanScItemStatRequest);
                if (Objects.nonNull(resultResult) && Objects.nonNull(resultResult.getResult())
                    && org.apache.commons.collections4.CollectionUtils.isNotEmpty(
                    resultResult.getResult().getContent())) {
                    totalResult.addAll(resultResult.getResult().getContent());
                }
            }

        } else {
            totalResult.addAll(firstResult.getResult().getContent());
        }

        log.info("业务员:" + bisUnitCode + "业务员月度结果:" + JSON.toJSONString(totalResult));

        int sum = Nullable.stream(totalResult).mapToInt(SalesPlanStatScItemSDO::getTaskCount).sum();

        return Optional.of(sum).orElse(0);
    }

    // 此方法若与0925分支发生冲突，以bugfix分支为准。（0925分支代码会删掉）
    // 拷贝loadDealForecastListV2 去除库存、信贷、月度计划等查询
    @Override
    public List<DealForecastOrderResponse> loadDealForecastListV3(DealForecastListRequest dealForecastListRequest) {
        List<DealForecastOrderResponse> dealForecastOrderResponses = new CopyOnWriteArrayList<>();
        //nowIds是主单id，新版本v2不用该字段
        //ids页面选中的子单id
        List<String> orderLineIds = dealForecastListRequest.getIds().stream().map(String::valueOf).collect(
            Collectors.toList());

        SearchForecastOrderRequest selectQuery = new SearchForecastOrderRequest();
        selectQuery.setLimit(100000);
        selectQuery.setSubLineBizId(orderLineIds);
        Result<List<ForecastOrderLineIndex>> selectedForecastOrderLines = queryForecastOrderLines(selectQuery);
        if (selectedForecastOrderLines == null || CollectionUtils.isEmpty(selectedForecastOrderLines.getResult())) {
            return dealForecastOrderResponses;
        }

        for (ForecastOrderLineIndex lineIndex : selectedForecastOrderLines.getResult()) {
            DealForecastOrderResponse dealForecastOrderResponse = convert2DealForecastOrderResponseByIndex(lineIndex,
                null, null, null, null);
            dealForecastOrderResponses.add(dealForecastOrderResponse);
        }

        return dealForecastOrderResponses;
    }

    @Override
    public Result<List<ForecastOrderLineIndex>> queryForecastOrderLinesForReport(
        SearchForecastOrderRequest pageQueryForecastRequest) {
        // 分页查询
        if (pageQueryForecastRequest.getStart() != null && pageQueryForecastRequest.getLimit() != null
            && pageQueryForecastRequest.getLimit() < 500) {
            return forecastOrderLineIndexService.queryForecastOrderLineByEsForReport(pageQueryForecastRequest);
        }

        int limit = 500;
        SearchForecastOrderRequest totalRequest = new SearchForecastOrderRequest();
        BeanUtils.copyProperties(pageQueryForecastRequest, totalRequest);
        totalRequest.setStart(0);
        totalRequest.setLimit(1);
        Result<List<ForecastOrderLineIndex>> totalResult = forecastOrderLineIndexService
            .queryForecastOrderLineByEsForReport(totalRequest);
        int totalCnt = totalResult.getTotal();
        int totalPage = (totalCnt + limit - 1) / limit;

        List<Future<List<ForecastOrderLineIndex>>> futureList = Lists.newArrayList();
        for (int pageNo = 0; pageNo < totalPage; pageNo++) {
            int start = pageNo * limit;
            CompletableFuture<List<ForecastOrderLineIndex>> future = CompletableFuture.supplyAsync(() -> {
                SearchForecastOrderRequest request = new SearchForecastOrderRequest();
                BeanUtils.copyProperties(pageQueryForecastRequest, request);
                request.setStart(start);
                request.setLimit(limit);
                Result<List<ForecastOrderLineIndex>> listResult = null;
                try {
                    listResult = forecastOrderLineIndexService.queryForecastOrderLineByEsForReport(request);
                    if (listResult == null || CollectionUtils.isEmpty(listResult.getResult())) {
                        return Lists.newArrayList();
                    }
                } catch (Exception e) {
                    log.error("多线程拉取预报订单数据异常", e);
                }
                List<ForecastOrderLineIndex> list = listResult.getResult();
                return list;
            }, monthSalesReportTaskExecutor);
            futureList.add(future);
        }
        List<ForecastOrderLineIndex> result = new ArrayList<>();
        try {
            for (Future<List<ForecastOrderLineIndex>> future : futureList) {
                List<ForecastOrderLineIndex> subList = future.get();
                result.addAll(subList);
            }
        } catch (Exception e) {
            log.error("获取多线程查询结果异常", e);
        }
        return Result.listSuccess(result, result.size());
    }

    private Integer getPlanDifferenceQuantity(ForecastOrderLineIndex forecastOrderLineIndex,Map<String,List<String>> mainOrderIdMap) {
        int planDifferenceQuantity = 0;
        try {
            /**
             * 查询客户地址Id
             */
            PageQueryAddressListRequest pageQueryAddressListRequest = PageQueryAddressListRequest.builder()
                .addressCode(forecastOrderLineIndex.getMainReceiveAddressCode())
                .channelCode(forecastOrderLineIndex.getMainChannelCode())
                .customerCode(forecastOrderLineIndex.getMainCustomerCode())
                .orgSaleOrganizationCode(forecastOrderLineIndex.getMainOrganizationCode())
                .itemGroup(forecastOrderLineIndex.getMainProductGroupCode())
                .build();
            String addressSDOId = "";
            log.info("查询客户地址Id参数:" + JSON.toJSONString(pageQueryAddressListRequest));
            PageQueryAddressListResponse pageQueryAddressListResponse = crPlatformEnhanceService.pageQueryAddressList(
                pageQueryAddressListRequest);
            log.info("查询客户地址Id返回:" + JSON.toJSONString(pageQueryAddressListResponse));
            if (Objects.nonNull(pageQueryAddressListResponse) && org.apache.commons.collections4.CollectionUtils
                .isNotEmpty(pageQueryAddressListResponse.getResult())) {
                List<CustomerAddressSDO> result1 = pageQueryAddressListResponse.getResult();
                CustomerAddressSDO customerAddressSDO = result1.get(0);
                addressSDOId = customerAddressSDO.getId();
            } else {
                throw new FunctionException("OTS-04-001-00-15-034");
            }

            //Integer totalPlanQty = 0;
            /**
             * 查询月度计划planId
             */
            PageQuerySalePlanRequest pageQuerySalePlanRequest = new PageQuerySalePlanRequest();
            /*String date = com.alibaba.citrus.cr.common.util.DateUtils.formatDate(new Date(), "yyyy-MM-dd");
            pageQuerySalePlanRequest.setPlanTime(date);*/
            Date date = new Date(forecastOrderLineIndex.getSubGmtCreate());

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM");
            String format = simpleDateFormat.format(date);
            pageQuerySalePlanRequest.setPlanTime(format);
            pageQuerySalePlanRequest.setOrgBusinessUnitCode(forecastOrderLineIndex.getMainBisUnitCode());
            pageQuerySalePlanRequest.setStatus(SalesPlanStatusEnum.PUBLISHED.getCode().toString());
            pageQuerySalePlanRequest.setLimit(1);
            String planId = "";
            log.info("查询月度计划PlanId参数:" + JSON.toJSONString(pageQuerySalePlanRequest));
            Result<PageResult<List<SalesPlanSDO>>> pageResultResult = salesPlanQueryService
                .pageQuerySalesPlanListInValid(pageQuerySalePlanRequest);
            log.info("查询月度计划PlanId返回:" + JSON.toJSONString(pageResultResult));
            if (Objects.nonNull(pageResultResult) && Objects.nonNull(pageResultResult.getResult()) &&
                org.apache.commons.collections4.CollectionUtils.isNotEmpty(pageResultResult.getResult().getContent())) {
                PageResult<List<SalesPlanSDO>> result = pageResultResult.getResult();
                List<SalesPlanSDO> content = result.getContent();
                SalesPlanSDO salesPlanSDO = content.get(0);
                planId = salesPlanSDO.getId() == null ? null : String.valueOf(salesPlanSDO.getId());

                /**
                 * 获取计划明细回复数量
                 */
                PageQuerySalesPlanLineList2Request pageQuerySalePlanRequestLine
                    = new PageQuerySalesPlanLineList2Request();
                pageQuerySalePlanRequestLine.setPlanId(planId);
                pageQuerySalePlanRequestLine.setCustomerAddressId(addressSDOId);//"11"
                pageQuerySalePlanRequestLine.setCustomerCode(
                    forecastOrderLineIndex.getMainCustomerCode());//"3730000712");
                pageQuerySalePlanRequestLine.setScItemId(
                    forecastOrderLineIndex.getSubScItemId());//"306188816041963901");
                // pageQuerySalePlanRequestLine.setManageEmployeeId(forecastOrderLineIndex.getMainSalesmanId());
                pageQuerySalePlanRequestLine.setBizType(SalesStatBizTypeEnum.SALESMAN.getOrganizationType());
                pageQuerySalePlanRequestLine.setBizId(forecastOrderLineIndex.getMainSalesmanId());
                pageQuerySalePlanRequestLine.setStart(0);
                pageQuerySalePlanRequestLine.setLimit(10);

                log.info("查询月度计划明细回复量入参:" + JSON.toJSONString(pageQuerySalePlanRequestLine));
                PageQuerySalesPlanLineList2Response pageResultResult1 = salesPlanService.pageQuerySalesPlanLineList2(
                    pageQuerySalePlanRequestLine);
                log.info("查询月度计划明细回复量返回:" + JSON.toJSONString(pageResultResult1));
                if (Objects.nonNull(pageResultResult1) && Objects.nonNull(pageResultResult1.getResult()) &&
                    org.apache.commons.collections4.CollectionUtils.isNotEmpty(pageResultResult1.getResult())) {
                    List<SalesPlanLineSDO2> salesPlanLineSDOS = pageResultResult1.getResult();
                    SalesPlanLineSDO2 salesPlanLineSDO = salesPlanLineSDOS.get(0);
                    planDifferenceQuantity = salesPlanLineSDO.getTaskCount();
                }
            }



            List<String> mainIdList = mainOrderIdMap.get(forecastOrderLineIndex.getMainSalesmanId() + "-" + forecastOrderLineIndex.getMainReceiveAddressCode() + "-" + DateUtils.getMonth(date));
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(mainIdList)){
                for (String mainOrderId : mainIdList) {
                    CountSaleOrderForAnalysisPositiveRequest positiveSale = new CountSaleOrderForAnalysisPositiveRequest();
                    positiveSale.setScItemId(forecastOrderLineIndex.getSubScItemId());
                    positiveSale.setMainOrderId(mainOrderId);log.info("查询统计销售子单发货数入参:" + JSON.toJSONString(positiveSale));
            CountSaleOrderForAnalysisPositiveResponse countSaleOrderForReportResponse = crB2bTradeCenterService
                .countSaleOrderForAnalysisPositive(positiveSale);
            log.info("查询统计销售子单发货数返回:" + JSON.toJSONString(countSaleOrderForReportResponse));
            if (Objects.nonNull(countSaleOrderForReportResponse)) {
                planDifferenceQuantity = new BigDecimal(planDifferenceQuantity).subtract(
                    new BigDecimal(countSaleOrderForReportResponse.getDeliveryAmount())).setScale(0,
                    RoundingMode.HALF_UP).intValue();
            }

                    CountSaleOrderForAnalysisNegativeRequest negativeRequest = new CountSaleOrderForAnalysisNegativeRequest();
                    negativeRequest.setScItemId(forecastOrderLineIndex.getSubScItemId());
                    negativeRequest.setMainOrderId(mainOrderId);
            log.info("查询统计销售子单退货数入参:" + JSON.toJSONString(negativeRequest));
            CountSaleOrderForAnalysisNegativeResponse negativeResponse = crB2bTradeCenterService
                .countSaleOrderForAnalysisNegative(negativeRequest);
            log.info("查询统计销售子单退货数返回:" + JSON.toJSONString(negativeResponse));
            if (Objects.nonNull(negativeResponse)) {
                planDifferenceQuantity = new BigDecimal(planDifferenceQuantity).add(
                    new BigDecimal(negativeResponse.getDeliveryAmount())).setScale(0, RoundingMode.HALF_UP).intValue();}
                }
            }
            //            else {
            //                throw new FunctionException("OTS-04-001-00-15-034");
            //            }
        } catch (Exception e) {
            planDifferenceQuantity = -1;
            log.error("ERROR:计划差量查询失败", e);
            e.printStackTrace();
        }
        return Math.max(planDifferenceQuantity, 0);
    }

    private DealForecastOrderResponse convert2DealForecastOrderResponseByIndex(ForecastOrderLineIndex lineIndex,
                                                                               Integer remainCnt, Double inventoryCnt, Long creditCnt, Date inventoryEarliestDom) {
        if (lineIndex == null) {
            return null;
        }

        DealForecastOrderResponse dealForecastOrderResponse = new DealForecastOrderResponse();
        //销售组织编码
        dealForecastOrderResponse.setOrganizationCode(lineIndex.getMainOrganizationCode());
        //分销渠道
        dealForecastOrderResponse.setSaleChannelCode(lineIndex.getMainSaleChannelCode());
        //产品组
        dealForecastOrderResponse.setProductGroupCode(lineIndex.getMainProductGroupCode());
        //售达方
        dealForecastOrderResponse.setCustomerCode(lineIndex.getMainCustomerCode());
        //明细id
        dealForecastOrderResponse.setId(String.valueOf(lineIndex.getSubId()));
        //主单id
        dealForecastOrderResponse.setMainOrderId(lineIndex.getSubMainOrderId());
        //预计恢复数量
        dealForecastOrderResponse.setPredictReplyAmount(
            lineIndex.getSubPredictReplyAmount() == null ? 0 : lineIndex.getSubPredictReplyAmount().intValue());
        //客户名称
        dealForecastOrderResponse.setCustomerName(lineIndex.getMainCustomerName());
        //送达方名称名称
        dealForecastOrderResponse.setReceiveDetailAddress(lineIndex.getMainReceiveDetailAddress());
        //分析原因
        dealForecastOrderResponse.setAnalysisReason(lineIndex.getSubAnalysisReason());
        //商品名称
        dealForecastOrderResponse.setScItemTitle(lineIndex.getSubScItemTitle());
        //商品名称
        dealForecastOrderResponse.setScItemName(lineIndex.getSubScItemTitle());
        //行号
        dealForecastOrderResponse.setSerialNumber(lineIndex.getSubSerialNumber());
        // 查询可用库存
        Double availableQuantity = Optional.ofNullable(inventoryCnt).orElse(0D);
        dealForecastOrderResponse.setInventory(BigDecimal.valueOf(availableQuantity).setScale(3, RoundingMode.FLOOR)
            .toString());

        /**
         * 货品生产日期
         * 由于es是使用时间戳返回结果  空的话会是0 所以特判
         */
        if (StringUtils.isNotBlank(lineIndex.getSubGoodsProductationTime()) && !("0").equals(
                lineIndex.getSubGoodsProductationTime())) {
            try {
                Date date = new Date(new BigDecimal(lineIndex.getSubGoodsProductationTime()).longValue());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String format = sdf.format(date);
                dealForecastOrderResponse.setGoodsProductationTime(format);
            } catch (Exception e) {
                log.error("ForecastOrderLineQueryRepositoryImpl|convert2DealForecastOrderResponseByIndex", e);
            }
        }else {
            if (Objects.nonNull(inventoryEarliestDom)){
            SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
            try {
                String  inventoryEarliestDomStr = simpleDateFormat.format(inventoryEarliestDom);
                dealForecastOrderResponse.setGoodsProductationTime(inventoryEarliestDomStr);
            } catch (Exception e) {
                log.error("format inventoryEarliestDom error,",e);
            }
        }}
        //查询库存最早生产日期

        //orderNo 订单号
        dealForecastOrderResponse.setOrderNo(String.valueOf(lineIndex.getMainId()));
        //预报数量
        dealForecastOrderResponse.setQuantity(lineIndex.getSubQuantity());
        //actualTotalReplyAmount 累计回复数量
        dealForecastOrderResponse.setActualTotalReplyAmount(
            lineIndex.getSubActualTotalReplyAmount() == null ? 0 : lineIndex.getSubActualTotalReplyAmount().intValue());
        //promotionId 促销Id
        dealForecastOrderResponse.setPromotionId(lineIndex.getSubActivityCode());
        //promotionDesc 促销描述
        dealForecastOrderResponse.setPromotionDesc(lineIndex.getSubActivityName());
        //unitPrice 单价
        dealForecastOrderResponse.setUnitPrice(lineIndex.getSubUnitPrice());
        //orderTotalFee 总金额
        dealForecastOrderResponse.setOrderTotalFee(lineIndex.getSubTotalFee());
        //salesOrderId 销售单号
        dealForecastOrderResponse.setSalesOrderId(lineIndex.getMainOuterOrderId());
        //消息说明
        dealForecastOrderResponse.setMessageIndicate("销售订单生成成功");
        //备注
        dealForecastOrderResponse.setDetailRemark(lineIndex.getSubDetailRemark());
        //信贷余额
        /**
         * 调用SAP信贷查询接口实时获取，不可编辑
         */
        if (creditCnt != null) {
            dealForecastOrderResponse.setCreditBalance(creditCnt);
        }

        //扣减预报可用库存
        /**
         * 1、调用可用库存查询API获取可用库存
         * 2、计算当前日期预报订单的累计未回复说量
         * 3、该值=1-2
         * 4、不可编辑
         */
        //获取当天已经使用的货品数量
        //通过接口获取每日库存减去已经使用的库存
        if (null != remainCnt) {
            Double deductionInventory = availableQuantity - remainCnt;
            dealForecastOrderResponse.setDeductionInventory(BigDecimal.valueOf(deductionInventory)
                .setScale(3, RoundingMode.FLOOR).toString());
        } else {
            dealForecastOrderResponse.setDeductionInventory(BigDecimal.valueOf(availableQuantity)
                .setScale(3, RoundingMode.FLOOR).toString());
        }

        /**
         * 设置业务单id
         */
        dealForecastOrderResponse.setOrderBizId(lineIndex.getMainOrderBizId());

        /**
         * 拒绝原因
         */
        dealForecastOrderResponse.setRefuseReason(lineIndex.getSubRefuseReason());
        return dealForecastOrderResponse;
    }

    private Long queryCustomerCredit(CreditQueryRequest request) {
        try {
            Result<CreditInfoSDO> result = creditQueryService.queryCreditBalance(request);
            CreditInfoSDO response = result.getResult();
            if (result.isSuccess() || response != null) {
                return MoneyUtil.formatRoundLong(response.getBalance());
            }
        } catch (Exception e) {
            log.error("ERROR:获取信贷余额失败 req:" + JSON.toJSONString(request), e);
        }
        return null;
    }

    //获取预计回复数量 * (常规价 或 活动价)
    private static String compute(Integer predictReplyAmount, String price) {
        if (predictReplyAmount == null || StringUtils.isBlank(price)) {
            return null;
        }
        return new BigDecimal(predictReplyAmount).multiply(new BigDecimal(price)).toString();
    }

}
